package com.yf.limiter.impl;

import com.yf.limiter.RateLimiter;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 固定窗口计数器限流算法
 * 核心思想：将时间划分为固定长度的窗口，每个窗口内允许固定数量的请求，窗口结束后计数器重置
 * 特点：实现简单、高效，但流量激增可能造成窗口很长时间无法接收请求
 */
public class FixedWindowCounterRateLimiter<T> implements RateLimiter<T> {
    // 窗口大小（毫秒）
    private final long windowSizeMs;
    //最大请求数
    private final int maxRequestsPerWindow;
    //窗口的计数器
    private final AtomicInteger currentRequestCount = new AtomicInteger(0);
    //开始时间（毫秒）
    private volatile long currentWindowStartTime;


    public FixedWindowCounterRateLimiter(long windowSizeMs, int maxRequestsPerWindow) {
        this.windowSizeMs = windowSizeMs;
        this.maxRequestsPerWindow = maxRequestsPerWindow;
        this.currentWindowStartTime = System.currentTimeMillis();
    }

    /**
     * 尝试获取请求许可
     */
    public boolean submit(T req) {
        long now = System.currentTimeMillis();

        // 1. 检查是否需要切换到新窗口
        if (now - currentWindowStartTime > windowSizeMs) {
            // 使用CAS原子操作重置窗口（避免并发问题）
            if (currentRequestCount.compareAndSet(currentRequestCount.get(), 0)) {
                currentWindowStartTime = now;
            }
            // 若CAS失败，说明其他线程已重置窗口，当前线程直接进入新窗口判断
        }

        // 2. 检查当前窗口请求数是否已达阈值
        int currentCount = currentRequestCount.get();
        if (currentCount >= maxRequestsPerWindow) {
            return false; // 限流
        }

        // 3. 计数器加1（原子操作，保证线程安全）
        return currentRequestCount.incrementAndGet() <= maxRequestsPerWindow;
    }

}
